001 /* 002 * Copyright 2003-2005 The Apache Software Foundation 003 * Copyright 2005 Stephen McConnell 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package net.dpml.cli.option; 018 019 import java.util.Collections; 020 import java.util.Comparator; 021 import java.util.List; 022 import java.util.ListIterator; 023 import java.util.Set; 024 025 import net.dpml.cli.DisplaySetting; 026 import net.dpml.cli.HelpLine; 027 import net.dpml.cli.OptionException; 028 import net.dpml.cli.WriteableCommandLine; 029 import net.dpml.cli.resource.ResourceConstants; 030 031 /** 032 * Handles the java style "-Dprop=value" opions 033 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 034 * @version 1.0.0 035 */ 036 public class PropertyOption extends OptionImpl 037 { 038 /** 039 * The default property option name. 040 */ 041 public static final String DEFAULT_OPTION_STRING = "-D"; 042 043 /** 044 * The default property option description. 045 */ 046 public static final String DEFAULT_DESCRIPTION = "Set property values."; 047 048 /** 049 * A default PropertyOption instance 050 */ 051 public static final PropertyOption INSTANCE = new PropertyOption(); 052 053 private final String m_optionString; 054 private final String m_description; 055 private final Set m_prefixes; 056 057 /** 058 * Creates a new PropertyOption using the default settings of a "-D" trigger 059 * and an id of 'D' 060 */ 061 public PropertyOption() 062 { 063 this( DEFAULT_OPTION_STRING, DEFAULT_DESCRIPTION, 'D' ); 064 } 065 066 /** 067 * Creates a new PropertyOption using the specified parameters 068 * @param optionString the trigger for the Option 069 * @param description the description of the Option 070 * @param id the id of the Option 071 */ 072 public PropertyOption( 073 final String optionString, final String description, final int id ) 074 { 075 super( id, false ); 076 m_optionString = optionString; 077 m_description = description; 078 m_prefixes = Collections.singleton( optionString ); 079 } 080 081 /** 082 * Indicates whether this Option will be able to process the particular 083 * argument. 084 * 085 * @param commandLine the CommandLine object to store defaults in 086 * @param argument the argument to be tested 087 * @return true if the argument can be processed by this Option 088 */ 089 public boolean canProcess( 090 final WriteableCommandLine commandLine, final String argument ) 091 { 092 return ( argument != null ) 093 && argument.startsWith( m_optionString ) 094 && ( argument.length() > m_optionString.length() ); 095 } 096 097 /** 098 * Identifies the argument prefixes that should be considered options. This 099 * is used to identify whether a given string looks like an option or an 100 * argument value. Typically an option would return the set [--,-] while 101 * switches might offer [-,+]. 102 * 103 * The returned Set must not be null. 104 * 105 * @return The set of prefixes for this Option 106 */ 107 public Set getPrefixes() 108 { 109 return m_prefixes; 110 } 111 112 /** 113 * Processes String arguments into a CommandLine. 114 * 115 * The iterator will initially point at the first argument to be processed 116 * and at the end of the method should point to the first argument not 117 * processed. This method MUST process at least one argument from the 118 * ListIterator. 119 * 120 * @param commandLine the CommandLine object to store results in 121 * @param arguments the arguments to process 122 * @throws OptionException if any problems occur 123 */ 124 public void process( 125 final WriteableCommandLine commandLine, final ListIterator arguments ) 126 throws OptionException 127 { 128 final String arg = (String) arguments.next(); 129 130 if( !canProcess( commandLine, arg ) ) 131 { 132 throw new OptionException( 133 this, 134 ResourceConstants.UNEXPECTED_TOKEN, 135 arg ); 136 } 137 138 final int propertyStart = m_optionString.length(); 139 final int equalsIndex = arg.indexOf( '=', propertyStart ); 140 final String property; 141 final String value; 142 143 if( equalsIndex < 0 ) 144 { 145 property = arg.substring( propertyStart ); 146 value = "true"; 147 } 148 else 149 { 150 property = arg.substring( propertyStart, equalsIndex ); 151 value = arg.substring( equalsIndex + 1 ); 152 } 153 commandLine.addProperty( property, value ); 154 } 155 156 /** 157 * Identifies the argument prefixes that should trigger this option. This 158 * is used to decide which of many Options should be tried when processing 159 * a given argument string. 160 * 161 * The returned Set must not be null. 162 * 163 * @return The set of triggers for this Option 164 */ 165 public Set getTriggers() 166 { 167 return Collections.singleton( m_optionString ); 168 } 169 170 /** 171 * Checks that the supplied CommandLine is valid with respect to this 172 * option. 173 * 174 * @param commandLine the CommandLine to check. 175 * @throws OptionException if the CommandLine is not valid. 176 */ 177 public void validate( WriteableCommandLine commandLine ) throws OptionException 178 { 179 // PropertyOption needs no validation 180 } 181 182 /** 183 * Appends usage information to the specified StringBuffer 184 * 185 * @param buffer the buffer to append to 186 * @param helpSettings a set of display settings @see DisplaySetting 187 * @param comp a comparator used to sort the Options 188 */ 189 public void appendUsage( 190 final StringBuffer buffer, final Set helpSettings, final Comparator comp ) 191 { 192 final boolean display = helpSettings.contains( DisplaySetting.DISPLAY_PROPERTY_OPTION ); 193 final boolean bracketed = helpSettings.contains( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED ); 194 195 if( display ) 196 { 197 buffer.append( m_optionString ); 198 if( bracketed ) 199 { 200 buffer.append( '<' ); 201 } 202 buffer.append( "property" ); 203 if( bracketed ) 204 { 205 buffer.append( '>' ); 206 } 207 buffer.append( "=" ); 208 if( bracketed ) 209 { 210 buffer.append( '<' ); 211 } 212 buffer.append( "value" ); 213 if( bracketed ) 214 { 215 buffer.append( '>' ); 216 } 217 } 218 } 219 220 /** 221 * The preferred name of an option is used for generating help and usage 222 * information. 223 * 224 * @return The preferred name of the option 225 */ 226 public String getPreferredName() 227 { 228 return m_optionString; 229 } 230 231 /** 232 * Returns a description of the option. This string is used to build help 233 * messages as in the HelpFormatter. 234 * 235 * @see net.dpml.cli.util.HelpFormatter 236 * @return a description of the option. 237 */ 238 public String getDescription() 239 { 240 return m_description; 241 } 242 243 /** 244 * Builds up a list of HelpLineImpl instances to be presented by HelpFormatter. 245 * 246 * @see HelpLine 247 * @see net.dpml.cli.util.HelpFormatter 248 * @param depth the initial indent depth 249 * @param helpSettings the HelpSettings that should be applied 250 * @param comp a comparator used to sort options when applicable. 251 * @return a List of HelpLineImpl objects 252 */ 253 public List helpLines( 254 final int depth, final Set helpSettings, final Comparator comp ) 255 { 256 if( helpSettings.contains( DisplaySetting.DISPLAY_PROPERTY_OPTION ) ) 257 { 258 final HelpLine helpLine = new HelpLineImpl( this, depth ); 259 return Collections.singletonList( helpLine ); 260 } 261 else 262 { 263 return Collections.EMPTY_LIST; 264 } 265 } 266 }